Repository navigation
fix: 调用 mediaRequestHeaders 补齐 HLS 媒体请求头 - #1
Open
fourbain-lab wants to merge 10 commits into
Open
fourbain-lab wants to merge 10 commits into
fourbain-lab wants to merge 10 commits into
Conversation
上游 native/core/app_stream.go 第 280-281 行只手动设了 User-Agent 和 Referer 两个头,遗漏了 Accept / Accept-Language / Sec-Fetch-Mode / Sec-Fetch-Dest / Origin 等媒体服务校验的关键头, 导致部分 HLS 媒体源返回 403 / Source error。 network_media.go:23-35 已实现 mediaRequestHeaders() 一次性补齐 全部 7 个头,本 commit 直接调用该函数以消除重复代码并确保头集合 与上游修复保持一致。
v1 patch (66a911d) 把 App Setter 调用改为 mediaRequestHeaders,但没修 红果 3 处 Referer 写死:provider_hongguo_playback.go:92 和 provider_hongguo_native_media.go:69 都写死 novel.snssdk.com, 实际 CDN 跨域 douyinvod.com 等 → 触发 403 防盗链。 v2 修复: 1. network_media.go mediaRequestHeaders 智能兜底: - 用 url.Parse + strings.EqualFold 严格比较 Host(防 strings.Contains a.com ⊂ b.a.com 误伤) - referer 与 request URL host 不一致时,自动用 request.URL 兜底 为同源 Referer - Origin 只取 scheme://host(去 path) 2. 删红果 2 处 hardcode novel.snssdk.com,留空 Referer: - provider_hongguo_playback.go:92 - provider_hongguo_native_media.go:69 留 hongguoduanju.com (provider_hongguo.go:238) 靠兜底逻辑处理跨域 CDN 3. network_media_test.go 加 7 个表驱动测试覆盖核心场景: - 同源保留原 referer - 空 referer 兜底 - 跨域 CDN 兜底(红果主场景) - 子域陷阱(防 Contains 误伤) - 大小写不敏感(EqualFold) - Referer 带 path 时 Origin 只取 host - Referer 解析失败时兜底 Co-Authored-By: Claude <noreply@anthropic.com>
根因分析(panel V3 三席收敛): 1. URL 过期真凶:红果 CDN URL 带字节 TOS 签名(l=...),有效期 ~30min 2. v2 patch 的跨域 Referer 兜底反而制造 403 (CDN 拒自己 host 作 Referer) 3. v1 patch 漏 app_preload.go 同源处理 v3 改动: - providerMedia 加 seriesID/videoID/source 字段 - provider_hongguo.go 末尾加 refreshHongguoMediaURL:复用 resolveHongguoPlaybackAPI,5s ctx 超时 - app_stream.go: 403/410 触发 refresh 重试一次,重用 Range/If-Range - app_preload.go:80/215 改用 mediaRequestHeaders 同源兜底 - network_media_test.go +49 行 (3 个 refresh RefererOverride case) - app_stream_test.go 新文件 (2 个 refresh 错误传播 case) debug 日志(验真凶后会撤): - media_refresh_triggered / refresh_hongguo_media_url_enter / media_refresh_ok / media_refresh_failed panel_invocation: claude_code=ok, codex=ok, agy=ok, ts=2026-10-04T20:23:23Z Refs: PR zhoufuweigg#1
V4A: - mediaRequestHeaders 删除跨域兜底(同源改写 Referer + Origin 注入) curl 测试 zhoufuweigg#4 已证 CDN 拒 '同源 Referer/Origin' (v11-hgweb.qznovelvod.com 403) - Referer 写死 'https://hongguoduanju.com/'(curl 测试 zhoufuweigg#2 已证 200) - provider_hongguo_playback.go + provider_hongguo_native_media.go Referer 从 '' 改为 'https://hongguoduanju.com/' - pubspec.yaml version 71 → 72 触发新 release tag 'app-v0.2.64-72',刷新 GitHub publishedAt 时间戳 - 保留 V3 recordDiagnostic 4 个日志看真凶 - 保留 V3 refreshHongguoMediaURL 兜底(如果 referer 真凶是 URL 过期仍能救) 不修 keystore(AM/AN/AP 等主银另拍) 不删 v3 的 debug 日志(待 V4A 装机再判断要不要撤)
红果 App API 返回的 video_list 现在包含 4 个 bytevc2 codec(播放器无 decoder) + 1 个 1080p h265_hvc1 variant(ExoPlayer 可播)。 V1-V7 的过滤逻辑: if codec == "bytevc2" || strings.Contains(strings.ToLower(gear_des_key), "bytevc2") 因为 h265_hvc1 1080p 的 gear_des_key 链里含 bytevc2 字面量(与 codec_type 字段 取值无关),导致该 variant 被错误跳过 -> 整个 video_list 空 -> 返回 "红果 App 未返回兼容的媒体" -> ExoPlayer 拿空响应 -> Source error。 V8 改为只比对 codec_type 字段: if codec == "bytevc2" 新增 regression test TestHongguoCodecFilterPreservesHevenWhenGearKeyMentionsBytevc2 锁住此 bug,确保未来 gear_des_key 字段含义变更时不会被错误过滤。 Root cause: V1-V7 都没嗅探真实 API 返回值,没用 curl 复刻 X-Gorgon 签名直接 打 https://api5-normal-sinfonlineb.fqnovel.com/novel/player/video_model/v1/。 本应一开始就这么做。
字节 CDN 实测: - 无 Referer = 206 ✓ - Referer=hongguoduanju.com = 403 denied by Referer ACL ❌ - Referer=novel.snssdk.com = 206 ✓ - Referer=byteicdn.com = 206 ✓ 红果流程 credentials==nil → credentials.apply() 不设 Referer → mediaRequestHeaders(Referer='') 因 if referer!='' guard 跳过 → 实际请求无 Referer 头 V8 fix 已修 codec 过滤,这次只动 Referer 一个旋钮 保留 V3 的 4 个 recordDiagnostic log(refresh_hongguo_media_url_enter / media_refresh_triggered / ok / failed)
红果 App API (/novel/player/video_model/v1) 5 个 variant 全是字节私有 codec
(bytevc1/bytevc2),Android ExoPlayer MediaCodec 不解 → Source error。
Web player (/player/{seriesID}/{videoID}) 返回标准 h264 MP4 (ffprobe 验证:
h264 High profile level 31, 720x1280),MediaCodec 100% 能解。
V10 改动:
1. resolveHongguoMedia: 调换 web/app 顺序 (web 先 app 后) — 6 行代码 + 注释
2. selectHongguoAppMedia: 加 bytevc1 过滤 — 1 行代码 + 注释 (defense-in-depth 防 reorder 回归)
约束:
- ≤10 行 (实 7 行)
- 不集成 codec
- 不改 build system
- 不动 web fallback 已存在的代码路径
验证:
- web dry probe: hongguoduanju.com/player/{id}/{id} 独立可拉 (无需 App 预热)
- ffprobe v26-hgweb + v11-hgweb 双 CDN: 都是 h264 High profile level 31
- Codex R1 + Codex R2 共识
- Agy R1 撒谎 (commit SHA 0dd4df3 不存在, GitHub API 422 拒绝)
panel_invocation: claude_code=ok, codex=ok, agy=FAIL(撒谎越权), ts=2026-10-06T13:55:00+08:00
合并 fengs2021/fix/android-cenc-playback (PR zhoufuweigg#2) 进主银 fork。 PR zhoufuweigg#2 真凶(vs V1-V10): - 0.2.64 把 Android 从 media_kit/libmpv 切成 LunaExoPlayer(package:video_player) - 红果内容是 CENC (AES-128-CTR) 加密,密钥 spade_a → plan.decryptionKey - ExoPlayer 不提供任何 DRM/解密接口 → 加密数据当明文喂 MediaCodec - 短视频蒙混过关,长视频 Source error(之前以为的 bytevc codec 问题是表象) - 切回 libmpv + decryption_key= 参数走原生 mpv 解密链路,AVD 实测 playable=true PR zhoufuweigg#2 顺手修 Go 代理 4 缺陷: 1. Range 兑现:CDN 忽略 Range 时代理自己跳前缀 + 限长度 + 补 206/Content-Range (TestNativeUpstreamIgnoringRangeStillHonoursOffsets) 2. 会话误回收:served/inflight 计数 + served(token)/usedAt(token) (TestNativeIdlePlaybackSessionSurvivesOtherSessions) 3. HLS 启发式误判:去掉 url.contains('hls'),改路径后缀 .m3u8/.m3u 4. Range 请求强制 Accept-Encoding: identity + 响应头立即 Flush(Media3 8s 连接超时兜底) PR zhoufuweigg#2 顺手修诊断能力: - lib/main.dart 启动日志改读 appVersion+duanjuBuildNumber 常量(不再硬编码 0.2.64+71) → 解决此前版本号误判问题 - 播放日记记密钥位数/线路/本地标志 - 64 条环形 probe 缓冲 + playbackProbe action 桥暴露 冲突解决: - pubspec.yaml: 选 PR zhoufuweigg#2 的 0.2.73+80(更新版本号 = 真 bug 修复后版本) - native/core/app_stream.go: 合并字段(主银 V3 加 seriesID/videoID + PR zhoufuweigg#2 加 inflight/served) + 保留 PR zhoufuweigg#2 的 5 个配套方法 (servedCount/inFlight/served/usedAt) - native/core/network_media.go: git 自动合并成功(两边都是单行 Set Accept-Encoding: identity) build trigger: workflow_dispatch 一次(push 触发那个会被 concurrency 自动 cancel) version: 0.2.73+80
- android/key.properties: 仓库级固定签名改由 Secrets 提供 - android/duanju_release.keystore: 公开 keystore 风险高,移除 - configure_signing.py 已优先用 secrets(任一 secrets 设置即接管)
根因: 红果服务端对最新 UA 全吐 bytevc1/bytevc2;web /player 前 3 集后强制 SSR 404。 诊断文档: /tmp/guoapp_v2/BYTEVC_DIAGNOSIS.md (双剧 8 集实测 + yt-dlp #9575 参考) D1: selectHongguoAppMedia 仿 yt-dlp preference=-100 降权 bytevc - 不再 continue 让 bytevc 完全消失 - bytevc Quality=0 + score -= 100000 → 永远垫底 - 当 App 服务端只返 bytevc 时,保留 last-resort variant 让 ExoPlayer 尝试 - TestH1 / TestH4 / TestH5 全 PASS (test 期望更新加 bytevc URL) D2: UA 降版本 (yt-dlp 备选方案) - 旧 UA: com.phoenix.read/73532 (Android 16 最新) - 新 UA: com.phoenix.read/70000 (Android 12 老版本) - 目标: 让服务端可能返回 h264 等老 codec - 风险: 服务端可能直接 403;失败则回滚 73532 测试修复 (D1 配套): - app_stream_range_test.go: zz14Reader → rangeProbeReader (refs PR#2 TestNativeUpstreamIgnoringRangeStillHonoursOffsets) - app_stream_test.go: newHongguoRefreshTestDownloader() 加 limiter 防空指针 - app_test.go: selectHongguoAppMedia 改 3 参数调用 - app_playback_routes_test.go: TestHongguoBackupAddressesAndCodecAlternatives 加 bytevc URL 到 want - provider_sources_parity_test.go: selectHongguoAppMedia 改 3 参数调用 catalog 持久化 3 FAIL (TestNativeHongguoCursorRestartsPerCatalog/RecoversSessionsAfterRestart/StalledCursorKeepsPartialItems) 不在本 commit scope,是独立 session/cursor bug。
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
修复:HLS 媒体请求头补齐(调用 mediaRequestHeaders)
问题背景
native/core/app_stream.go第 280-281 行在创建媒体上游请求时,只手动设置了User-Agent和Referer两个头,遗漏了媒体服务端校验所需的其余 5 个关键请求头:Accept: */*Accept-Language: zh-CN,zh;q=0.9Sec-Fetch-Mode: corsSec-Fetch-Dest: emptyOrigin: <referer 解析>→ 症状:部分 HLS 源返回
403 Forbidden或前端报Source error,与 README 中描述的"上游 v0.2.64+71 根除 Source error"目标不一致。修复内容
network_media.go:23-35已实现mediaRequestHeaders(request, referer)函数,一次性补齐全部 7 个请求头(包括已被手动设置的 UA / Referer)。本 PR 直接调用该函数,替换原 280-281 两行手动设头的代码,消除重复并保证头集合与上游其他路径一致。
改动
测试
git applyexit=0,无冲突flutter build apk备注
本 PR 由
fourbain-lab账号提交(fork + patch 流程自动化),如需调整 commit 作者署名请告知。